package com.blockchain.wmm.core.service;

import com.blockchain.wmm.block.bean.Block;
import com.blockchain.wmm.block.bean.BlockBody;
import com.blockchain.wmm.block.bean.BlockHeader;
import com.blockchain.wmm.block.bean.Instruction;
import com.blockchain.wmm.block.merkle.MerkleTree;
import com.blockchain.wmm.common.CommonUtil;
import com.blockchain.wmm.common.Sha256;
import com.blockchain.wmm.common.exception.TrustSDKException;
import com.blockchain.wmm.core.requestBody.BlockRequestBody;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.Collectors;

/**
 * @author  wangzun
 * blockService
 * */
@Service
public class BlockService {
    /**
     * 没有引入数据持久化机制之前,先写入一个测试队列
     * */
    public  static List<Block> queue;
    static {
        queue = new ArrayList<>(1024);
    }
    @Value("${version}")
    private int version;
    @Resource
    private InstructionService instructionService;
    public String check(BlockRequestBody blockRequestBody) throws TrustSDKException{
        if(blockRequestBody == null || blockRequestBody.getBlockBody() == null || StringUtils.isEmpty(blockRequestBody.getPublicKey())) {
            return "请求参数缺失";
        }
        List<Instruction> instructions = blockRequestBody.getBlockBody().getInstructions();
        if(CollectionUtils.isEmpty(instructions)) {
            return "指令集不能为空";
        }
        for (Instruction instruction : instructions) {
            if(!blockRequestBody.getPublicKey().equals(instruction.getPublicKey())) {
                return "指令内公钥与传入公钥不匹配";
            }
            if(!instructionService.checkSign(instruction)) {
                return "签名校验不通过";
            }
            if(!instructionService.checkHash(instruction)) {
                return "hash校验不通过";
            }
        }
        return null;
    }

    /**
     * 生成一个新的区块
     * @param  blockRequestBody BlockRequestBody
     * @return  Block
     * */
    public Block addBlock(BlockRequestBody blockRequestBody) {
        BlockBody blockBody = blockRequestBody.getBlockBody();
        List<Instruction> instructions = blockBody.getInstructions();
        List<String> hashList = instructions.stream().map(Instruction::getHash).collect(Collectors.toList());
        BlockHeader blockHeader = new BlockHeader();
        blockHeader.setHashList(hashList);

        //计算所有指令的hashRoot
        blockHeader.setHashMerkleRoot(new MerkleTree(hashList).build().getRoot());
        blockHeader.setPublicKey(blockRequestBody.getPublicKey());
        blockHeader.setTimeStamp(CommonUtil.getNow());
        blockHeader.setVersion(version);
        blockHeader.setNumber(new Long(queue.size() + 1));
        blockHeader.setHashPreviousBlock(queue.size() == 0 ? "0" : queue.get(queue.size() - 1).getHash());

        Block block = new Block();
        block.setBlockBody(blockBody);
        block.setBlockHeader(blockHeader);
        block.setHash(Sha256.sha256(blockHeader.toString() + blockBody.toString()));
        //所有数据组装完成之后应发送到共识机制,等待校验后落地生成
        //之后分别引入pbft , dpos, pos测试.
        //测试先直接写入模拟queue
        queue.add(block);
        return block;
    }

    public List<Block> query() {
        return queue.size() > 10 ? queue.subList(queue.size() - 10,queue.size()) : queue;
    }
}
